/*
 * Copyright (c) 2011-2021, baomidou (jobob@qq.com).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cc.siyecao.mapper.wrapper;

import cc.siyecao.mapper.conditions.Group;
import cc.siyecao.mapper.conditions.Join;
import cc.siyecao.mapper.conditions.Order;
import cc.siyecao.mapper.enums.SqlOrder;

import java.util.Arrays;
import java.util.List;

import static java.util.stream.Collectors.joining;

/**
 * 条件构造抽象类
 */
@SuppressWarnings("all")
public abstract class AbstractWrapper<W, R, T> extends AbstractCompareWrapper<W, R, T> implements Join<W>, Group<W, R>, Order<W, R> {

    @Override
    public W last(boolean condition, String endSql) {
        return maybeDo( condition, () -> this.endSql.setStringValue( endSql ) );
    }

    @Override
    public W comment(boolean condition, String comment) {
        return maybeDo( condition, () -> this.sqlComment.setStringValue( comment ) );
    }

    @Override
    public W first(boolean condition, String firstSql) {
        return maybeDo( condition, () -> this.startSql.setStringValue( firstSql ) );
    }

    @Override
    public W apply(boolean condition, String applySql, Object... value) {
        return addCondition( condition, String.format( applySql, value ) );
    }

    @Override
    public W apply(boolean condition, String applySql) {
        return addCondition( condition, applySql );
    }

    @Override
    public W groupBy(boolean condition, R... columns) {
        return maybeDo( condition, () -> {
            if (columns != null && columns.length > 0) {
                groupByClause.addString( columnsName( columns ) );
            }
        } );
    }

    @Override
    public W orderBy(boolean condition, SqlOrder sqlOrder, R column) {
        return maybeDo( condition, () -> orderBy( column, sqlOrder ) );
    }

    @Override
    public W orderBy(boolean condition, SqlOrder sqlOrder, R... columns) {
        return maybeDo( condition, () -> {
            if (columns != null && columns.length > 0) {
                for (int i = 0; i < columns.length; i++) {
                    orderBy( columns[i], sqlOrder );
                }
            }
        } );
    }

    /**
     * 通过方法引用方式设置排序字段
     *
     * @param column   排序列的方法引用
     * @param sqlOrder 排序方式
     * @return Example
     */
    private void orderBy(R column, SqlOrder sqlOrder) {
        orderByClause.addString( columnName( column ) + " " + sqlOrder );
    }

    /**
     * 获取 columnNames
     */
    String columnsName(R... columns) {
        return Arrays.stream( columns ).map( this::columnName ).collect( joining( COMMA ) );
    }

    /**
     * 多字段转换为逗号 "," 分割字符串
     *
     * @param columns 多字段
     */
    String columnsName(List<R> columns) {
        return columns.stream().map( this::columnName ).collect( joining( COMMA ) );
    }

}
